#ifndef YIG_H
#define YIG_H

// System includes
#include <QObject>
#include <QSemaphore>
#include <QThread>
#include <QTimer>

// Local includes
#include "gui/yigmainwindow.h"
#include "gui/yiggraphicsview.h"
#include "interface/channel/yignetworkchannel.h"
#include "gui/yigsynthmenu.h"
#include "gui/yigchat.h"
#include "sc++/sclang.h"
#include "network/yigclient.h"
#include "oscpack/osc/OscOutboundPacketStream.h"
#include "graphics/yigsynthgraphic.h"
#include "gui/yigloginmenu.h"
#include "gui/yigscore.h"

class YigPacketListener;

/**
*  Main class that organizes the various higher level elements of the program
*
*/
class Yig : public QObject
{
    Q_OBJECT

public:

    /** The number of network channels in Yig. Right now it is 1.
    *   We want 4 channels, however it will have to be worked out how to have 4 different YigNetworkChannels, and only
    *   1 YigNetworkChannelView
    */
    static const int NUMBER_OF_NETWORK_CHANNELS = 1;

    /**
    *   Yig constructor
    *   @param bool Indicates whether the program is in online or offline mode (on/off osc networking)
    *   @param onlineBool* yigClient osc networking client
    *   @param SCLang* scLang Pointer to the instance of sc lang we are using
    *   @param QString The application directory
    *   @param QSemaphore* a pointer to a semaphore that ensures proper clean up
    */
    Yig(bool onlineBool, YigClient* yigClient, SCLang* scLang,
        QString appDirectory, QSemaphore* wait4CleanupDone);

    /**
    * Yig Deconstructor, kill yo pointerz f00
    */
    ~Yig();

    /**
    *   setActiveChannel Sets the active channel which effects drag/drop ability and interactivity
    *   @param int channelNum Number of the active channel and channelView
    */
    void setActiveChannel(int channelNum);

    /**
    *   sendCthulhu sends takes a command, packages it as an osc packet and gives it to the client to send to OSCthulhu
    *   @param cont char* command The command as a string to be sent to the local OSCthulhu client over osc
    */
    void sendCthulhu(const char* command);

    /**
    *   sendCthulhu sends takes a command, packages it as an osc packet and gives it to the client to send to OSCthulhu
    *   @param cont char* command The command as a string to be sent to the local OSCthulhu client over osc
    *   @param cont char* value The value as an int to be sent
    */
    void sendCthulhu(const char* command, const char* value);

    /**
    *   sendCthulhu sends takes a command, packages it as an osc packet and gives it to the client to send to OSCthulhu
    *   @param cont char* command The command as a string to be sent to the local OSCthulhu client over osc
    *   @param int value The value as an int to be sent
    */
    void sendCthulhu(const char* command, int value);

    /**
    *   sendCthulhu sends takes a command, packages it as an osc packet and gives it to the client to send to OSCthulhu
    *   @param float command The command as a float to be sent to the local OSCthulhu client over osc
    */
    void sendCthulhu(const char* command, float value);

    /**
    *   requestCreateSynth Request the oscthulhu server to create a new synth
    *   @param const char* mapKey The map key for the synth to be created
    *   @param const char* The name of the synth def to use for this synth
    *   @param int xPos The x coordinate for the synth in the gui
    *   @param int yPos The y coordinate for the synth in the gui
    *   @param float the randomized first parameter
    *   @param float the randomized second parameter
    */
    void requestCreateSynth(const char* mapKey, const char* synthName, int xPos, int yPos, float param1, float param2);

    /**
    *   requestDeleteSynth Request the oscthulhu server to delete a synth
    *   @param const char* mapKey The map key for the synth to be deleted
    */
    void requestDeleteSynth(const char* mapKey);

    /**
    *   Updates the synth position over the network
    *   @param const char* The map key for the synth to change
    *   @param QPoint The new point where the synth is
    */
    void updateSynthPosition(const char* mapKey, QPoint point);

    /**
    *   Send a synth parameter modulation over the network
    *   @param const char* The map key for the synth
    *   @param float the new value of the parameter
    */
    void updateSynthParam1(const char* mapKey, float value);

    /**
    *   Send a synth parameter modulation over the network
    *   @param const char* The map key for the synth
    *   @param float the new value of the parameter
    */
    void updateSynthParam2(const char* mapKey, float value);

    /**
    *   Sets up all the signal/slots connections between the YigPacketListener and other various objects for osc networking
    *   @param YigPacketListener pointer to the packet listener
    */
    void setupNetworkConnections(YigPacketListener* listener);

    /** login information for the oscthulu networking */
    LogInInformation loginInfo;


public slots:

    /**
    *   called when a parameter for a synth has changed
    *   @param QString mapKey The key for the synth that has changed
    *   @param YigSynthGraphic::ParamType The type of parameter (param1 or param2)
    *   @param float The new value for the parameter
    */
    void updateSynthParam(QString mapKey, YigSynthGraphic::ParamType paramType, float value);

    /**
    *   emitted when a synth is moved by the local user
    *   @param QString the map key for the synth that moved
    *   @param QPointF the new position
    */
    void updateSynthPosition(QString mapKey, QPointF point);

    /**
    *   updateCursorPosition broadcasts the current position of the cursor to the other users
    *   @param QPoint pos the position of the cursor
    */
    void updateCursorPosition(QPoint pos);

    /**
    *   called when the selected state of the synth changes locally
    *   @param QString the map key for the synth
    *   @param int The selected state bool represented as an int
    */
    void synthSelectedChanged(QString mapKey, int selected);

    /** creates the synth menu, called once the sc synth server has booted */
    void createSynthMenu();

    /** This is called when the main application is attempting to quit, allowing us to clean up threads and such */
    void handleQuit();

    /** once everything has cleaned up we finalize the quitting process by freeing the semaphore */
    void finishQuit();

    void networking(bool networking);

    /** called when we get a reply from the server with our user name */
    void createCursorObject();

signals:

    /** Emitted when Yig is itself quitting */
    void quitting();

private:

    /** sets up OSCthulhu networking */
    void beginOSCthulhuNetworking();

    /** shutsdown OSCthulhu networking and cleans up */
    void endOSCthulhuNetworking();

    /** sends the login to oscthulhu*/
    void login();

    /** packet size used for osc packets */
    static const int PACKET_BUFFER_SIZE = 1024;

    /** buffer used for osc packers */
    char packetBuffer[PACKET_BUFFER_SIZE];
    /** packet stream for osc networking */
    osc::OutboundPacketStream packet;
    /** OSC networking client */
    YigClient* mYigClient;
    /** The port to send messages to for oscthulhu networking */
    int mOSCthulhuPort;
    /** thread the osc client runs in */
    //QThread clientThread;
    /** our instance of the scLang client */
    SCLang* mSCLang;
    /** pointer to semaphore that ensures proper cleanup before shutdown */
    QSemaphore* wait4CleanupDone;
    /** the main window in which all other gui elements reside */
    YigMainWindow mainWindow;
    ///** list of NetworkChannels */
    //QList<YigNetworkChannel*> channelList;
    /** interfaces sclang with the graphics */
    YigNetworkChannel* networkChannel;
    /** Drag/drop menu for synth object creation */
    YigSynthMenu* synthMenu;
    /** The chat window */
    YigChat yigChat;
    /** current channel of the local user */
    int currentUserChannel;
    /** used to trigger auto cables after the networking client boots up */
    QTimer startUpTimer;
    /** the directory for the Yig application */
    QString mAppDirectory;
    /** pop up when the server is booting */
    YigSCSynthBootMenu bootMenu;
    /** popup menu that logs the user on/off the oscthulhu server */
    YigLogInMenu* logInMenu;
    /** floating menu for score display */
    YigScore* scoreWindow;
};

#endif // YIG_H
